/*
 * ISearchProtocol.cs
 * 
 * Microsoft Office SharePoint Server Managed Protocol Handler
 * 
 * Author: John Kozell (johnkoz@microsoft.com)
 *         Microsoft Coroporation
 * 
 * This code is an adaptation from, and interpretation of, the original SPS 2001 SDK
 * and has been updated with available information at the time of writing.
 * Not all the delcarions and alogrithms have been verified and tested
 * and there is no guarantee that they are accurate or valid, now or in the future.
 * 
 * The .NET Managed COM Interop approach contained herin was NOT created in cooperation
 * with the Microsoft SharePoint product group and has not been officially endorced
 * by Microsoft and therefore is not supported. The user of this code assumes any
 * and all risk with its use and should proceed with discression.
 * 
 * THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
 * PARTICULAR PURPOSE.
 */

using System;
using System.Runtime.InteropServices;

#region "Windows Data Types"
// http://msdn.microsoft.com/en-us/library/aa383751(VS.85).aspx
using BOOL = System.Int32;     // typedef int BOOL;
using WORD = System.UInt16;    // typedef unsigned short WORD;
using DWORD = System.UInt32;   // typedef unsigned long DWORD;
using SHORT = System.Int16;    // typedef short SHORT;
using USHORT = System.UInt16;  // typedef unsigned short USHORT;
using INT = System.Int32;      // typedef int INT;
using UINT = System.UInt32;    // typedef unsigned int UINT;
using LONG = System.Int32;     // typedef long LONG;
using ULONG = System.UInt32;   // typedef unsigned long ULONG;
using FLOAT = System.Single;   // typedef float FLOAT;
using LPCWSTR = System.String; // typedef CONST WCHAR *LPCWSTR; 
using LPWSTR = System.String;  // typedef WCHAR *LPWSTR;
using LCID = System.UInt32;    // typedef DWORD LCID;

using CLSID = System.Guid;
using VARTYPE = System.UInt16;
using PROPID = System.UInt32;
using DOUBLE = System.Double;
#endregion


public class PROPSET_SEARCH
{
    public static Guid GUID = new Guid("49691c90-7e17-101a-a91c-08002b2ecda9");
    public enum PID : uint
    {
       URL = 9
    }
}

public class PROPSET_DOCUMENTS
{
    public static Guid GUID = new Guid("F29F85E0-4FF9-1068-AB91-08002B27B3D9");
    public enum PID : uint
    {
        TITLE    = 2,
        SUBJECT  = 3,
        AUTHOR   = 4,
        KEYWORDS = 5,
        COMMENTS = 6
    }
}

public class PROPSET_GATHERER
{
	public static Guid GUID = new Guid("0b63e343-9ccc-11d0-bcdb-00805fccce04");
    public enum PID : uint
    {
        DIRLINK                 = 0x2, //VT_LPWSTR only links found in the directories
        LOCAL_FILE              = 0x3, //VT_LPWSTR file name of the local copy of the document
        HOST                    = 0x4, //VT_LPWSTR host name of the document
        REDIRECTED_URL          = 0x5, //VT_LPWSTR real URL
        SECURITY                = 0x6, //VT_BLOB - security descriptor that contains OWNER, GROUP and DACL information
        DIRECTORY               = 0x7, //VT_BOOL, flag indicates if the document is a directory
        SECURITY_PROVIDER       = 0x8, //VT_CLSID - security provider CLSID
        DIRLINK_WITH_TIME       = 0xc, //VT_VARIANT|VT_VECTOR (VT_LPWSTR, VT_FILETIME)
        SECURITY_UPDATE_DIRLINK = 0xf, //VT_LPWSTR update only security attributes of the document
        LAST_MODIFIED           = 0x10 //timestamp of last modification
    }
}

public class PROPSET_STORAGE
{
    public static Guid GUID = new Guid("b725f130-47ef-101a-a5f1-02608c9eebac");
    public enum PID : uint
    {
        DIRECTORY        = 0x00000002,
        CLASSID          = 0x00000003,
        STORAGETYPE      = 0x00000004,
        VOLUME_ID        = 0x00000005,
        PARENT_WORKID    = 0x00000006,
        SECONDARYSTORE   = 0x00000007,
        FILEINDEX        = 0x00000008,
        LASTCHANGEUSN    = 0x00000009,
        NAME             = 0x0000000a,
        PATH             = 0x0000000b,
        SIZE             = 0x0000000c,
        ATTRIBUTES       = 0x0000000d,
        WRITETIME        = 0x0000000e,
        CREATETIME       = 0x0000000f,
        ACCESSTIME       = 0x00000010,
        CHANGETIME       = 0x00000011,
        ALLOCSIZE        = 0x00000012,
        CONTENTS         = 0x00000013,
        SHORTNAME        = 0x00000014,
        MAX              = 0x00000014,
        CSTORAGEPROPERTY = 0x15
    }
}

[ComImport]
[Guid("0b63e385-9ccc-11d0-bcdb-00805fccce04")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IProtocolHandlerSite // TODO. Not tested, might needs some tweaks.
{
    [PreserveSig]
    ISearchProtocolReturnCodes GetFilter(
        ref CLSID pclsidObj, 
        [MarshalAs(UnmanagedType.LPWStr)]
        string pcwszContentType, 
        [MarshalAs(UnmanagedType.LPWStr)]
        string pcwszExtension, 
        System.IntPtr ppFilter);
}


public enum PROXY_ACCESS
{
	PROXY_ACCESS_PRECONFIG = 0,
	PROXY_ACCESS_DIRECT	= PROXY_ACCESS_PRECONFIG + 1,
	PROXY_ACCESS_PROXY	= PROXY_ACCESS_DIRECT + 1
}


public enum AUTH_TYPE
{
	eAUTH_TYPE_ANONYMOUS = 0,
	eAUTH_TYPE_NTLM = eAUTH_TYPE_ANONYMOUS + 1,
	eAUTH_TYPE_BASIC = eAUTH_TYPE_NTLM + 1
}


[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct TIMEOUT_INFO
{
	public DWORD dwSize;
	public DWORD dwConnectTimeout;
	public DWORD dwDataTimeout;
};


[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct PROXY_INFO
{
	public DWORD dwSize;
	public LPCWSTR pcwszUserAgent;
	public PROXY_ACCESS paUseProxy;
	public BOOL fLocalBypass;
	public DWORD dwPortNumber;
	public LPCWSTR pcwszProxyName;
	public LPCWSTR pcwszBypassList;
}


[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct AUTHENTICATION_INFO
{
	public DWORD dwSize;
	public AUTH_TYPE atAuthenticationType;
	public LPCWSTR pcwszUser;
	public LPCWSTR pcwszPassword;
}


public struct INCREMENTAL_ACCESS_INFO
{
	public DWORD dwSize;
	public FILETIME ftLastModifiedTime;
}


public struct ITEM_INFO
{
	public DWORD dwSize;
	public LPCWSTR pcwszFromEMail;
	public LPCWSTR pcwszApplicationName;
	public LPCWSTR pcwszCatalogName;
	public LPCWSTR pcwszContentClass;
} 


[ComImport]
[ComVisible(true)]
[Guid("c73106ba-ac80-11d1-8df3-00c04fb6ef4f")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface ISearchProtocol
{
    [PreserveSig]
    ISearchProtocolReturnCodes Init(
        [InAttribute]
        ref TIMEOUT_INFO pTimeoutInfo, 
        IProtocolHandlerSite 
        pProtocolHandlerSite, 
        [InAttribute]
        ref PROXY_INFO pProxyInfo);

    [PreserveSig]
    ISearchProtocolReturnCodes CreateAccessor(
        [InAttribute, MarshalAs(UnmanagedType.LPWStr)]
        string pcwszURL, 
        [InAttribute]
        ref AUTHENTICATION_INFO pAuthenticationInfo, 
        [InAttribute]
        ref INCREMENTAL_ACCESS_INFO pIncrementalAccessInfo, 
        [InAttribute]
        ref ITEM_INFO pItemInfo, 
        out IUrlAccessor ppAccessor);

    [PreserveSig]
    ISearchProtocolReturnCodes CloseAccessor(
        IUrlAccessor pAccessor);

    [PreserveSig]
    ISearchProtocolReturnCodes ShutDown();
}

public enum ISearchProtocolReturnCodes : uint
{
    PRTH_E_COMM_ERROR           = 0x80041200, //  A communication error has occurred.
    PRTH_E_OBJ_NOT_FOUND        = 0x80041201, //  The object was not found.
    PRTH_E_REQUEST_ERROR        = 0x80041202, //  The options used are not supported. Make sure your version of Internet Explorer is supported.
    PRTH_S_NOT_MODIFIED         = 0x00041203, //  The content has not changed.
    PRTH_E_ACCESS_DENIED        = 0x80041205, //  Access is denied. Make sure the account used to access this URL is the correct account.
    PRTH_E_SERVER_ERROR         = 0x80041206, //  An error has occurred on the server. Make sure the server is functional.
    PRTH_E_NOT_REDIRECTED       = 0x80041207, //  The redirected URL does not exist. Make sure the source URL is redirecting to an accessible URL.
    PRTH_E_BAD_REQUEST          = 0x80041208, //  The request was invalid, because of an apparent error in the URL. Verify the URL is valid.
    PRTH_S_ACL_IS_READ_EVERYONE = 0x00041210, //  The Access Control List has successfully been changed so that it is readable by everyone.
    PRTH_E_ACL_IS_READ_NONE     = 0x80041211, //  The item will not be indexed, because Search has determined that the object's Access Control List allows no one to read the item. Make sure this is the desired behavior.
    PRTH_E_ACL_TOO_BIG          = 0x80041212, //  Search will not index the item, because its Access Control List exceeded 64 KB. Make sure the item has a valid Access Control List.
    PRTH_S_NOT_ALL_PARTS        = 0x8004121B, //  Some parts of this document cannot be accessed.

    GTHR_E_URL_EXCLUDED         = 0x80040D07, //  The specified address was excluded from the index. The crawl rules may have to be modified to include this address.
    GTHR_E_VALUE_NOT_AVAILABLE  = 0x80040D25, //  The requested value was not set by the filter process. This is a recoverable internal error. The document may still succeed.
}